home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Text / WASTE 1.3a6 / Demo / Source / WEDemoFiles.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-12-01  |  12.0 KB  |  486 lines  |  [TEXT/CWIE]

  1. /*
  2.     WASTE Demo Project:
  3.     File Handling
  4.  
  5.     Copyright © 1993-1997 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11.  
  12. #ifndef __WEDEMOAPP__
  13. #include "WEDemoIntf.h"
  14. #endif
  15.  
  16. #ifndef __ERRORS__
  17. #include <Errors.h>
  18. #endif
  19.  
  20. #ifndef __FOLDERS__
  21. #include <Folders.h>
  22. #endif
  23.  
  24. #define    kFileNotOpened    -1
  25.  
  26. OSErr ReadTextFile ( const FSSpec * pFileSpec, WEReference we )
  27. {
  28.     SInt16 dataForkRefNum = kFileNotOpened;
  29.     SInt16 resForkRefNum = kFileNotOpened;
  30.     Handle hText = nil;
  31.     Handle hStyles = nil;
  32.     Handle hSoup = nil;
  33.     Handle hFontTable = nil;
  34.     Size textSize;
  35.     Boolean wasChanged = false;
  36.     OSErr err;
  37.  
  38.     //    open the data fork with read-only permission
  39.     if ((err = FSpOpenDF(pFileSpec, fsRdPerm, &dataForkRefNum)) != noErr)
  40.         goto cleanup;
  41.  
  42.     //    get data fork size
  43.     if ((err = GetEOF(dataForkRefNum, &textSize)) != noErr)
  44.         goto cleanup;
  45.  
  46.     //    set the position in the file from where to start reading
  47.     if ((err = SetFPos(dataForkRefNum, fsFromStart, 0L)) != noErr)
  48.         goto cleanup;
  49.  
  50.     //    try to allocate a handle that large, use temporary memory if available
  51.     if ((err = NewHandleTemp(textSize, &hText)) != noErr)
  52.         goto cleanup;
  53.  
  54.     //    read in the text
  55.     HLock(hText);
  56.     err = FSRead(dataForkRefNum, &textSize, *hText);
  57.     HUnlock(hText);
  58.     if (err != noErr)
  59.         goto cleanup;
  60.  
  61.     //    see if the file has a resource fork
  62.     //    FSpOpenResFile will return -1 if it fails
  63.     if ( ( resForkRefNum = FSpOpenResFile( pFileSpec, fsRdPerm ) ) != kFileNotOpened )
  64.     {
  65.         //    look for a style scrap resource (get the first one; the resource ID doesn't matter)
  66.         if ((hStyles = Get1IndResource(kTypeStyles, 1)) != nil)
  67.         {
  68.             DetachResource(hStyles);
  69.         }
  70.  
  71.         //    look for a soup resource as well
  72.         if ((hSoup = Get1IndResource(kTypeSoup, 1)) != nil)
  73.         {
  74.             DetachResource(hSoup);
  75.         }
  76.  
  77.         //    finally, look for a font table resource
  78.         if ((hFontTable = Get1IndResource(kTypeFontTable, 1)) != nil)
  79.         {
  80.             DetachResource(hFontTable);
  81.         }
  82.     }
  83.  
  84.     //    if both a style scrap and a font table were found,
  85.     //    re-map font IDs in the style scrap
  86.     if ((hStyles != nil) && (hFontTable != nil))
  87.     {
  88.         if ((WEUpdateFontTable(hFontTable, nil, &wasChanged) == noErr) && wasChanged)
  89.         {
  90.             WEUpdateStyleScrap((StScrpHandle) hStyles, hFontTable);
  91.         }
  92.     }
  93.  
  94.     //    insert the text into the WE record
  95.     HLock(hText);
  96.     if ((err = WEInsert(*hText, textSize, (StScrpHandle) hStyles, hSoup, we)) != noErr)
  97.         goto cleanup;
  98.  
  99.     //    set the insertion point at the beginning of the text
  100.     WESetSelection(0, 0, we);
  101.  
  102.     //    reset the WE instance modification count
  103.     WEResetModCount( we );
  104.  
  105. cleanup:
  106.     // display an alert box if anything went wrong
  107.     if (err != noErr)
  108.     {
  109.         ErrorAlert( err );
  110.     }
  111.  
  112.     ForgetHandle(&hText);
  113.     ForgetHandle(&hStyles);
  114.     ForgetHandle(&hSoup);
  115.     ForgetHandle(&hFontTable);
  116.  
  117.     if ( dataForkRefNum != kFileNotOpened )
  118.     {
  119.         FSClose(dataForkRefNum);
  120.         dataForkRefNum = kFileNotOpened;
  121.     }
  122.  
  123.     if ( resForkRefNum != kFileNotOpened )
  124.     {
  125.         CloseResFile(resForkRefNum);
  126.         resForkRefNum = kFileNotOpened;
  127.     }
  128.  
  129.     return err;
  130. }
  131.  
  132. // I added a bunch of other functionality to WriteTextFile(), mostly to show how to use
  133. // temp files, check for locked files, etc. ( all along Apple's recommended way of
  134. // doing things.  - JCD
  135.  
  136. OSErr WriteTextFile ( const FSSpec * pFileSpec, WEReference we )
  137. {
  138.     FInfo fileInfo ;
  139.     Size textSize ;
  140.     Boolean replacing ;
  141.     SInt16 dataForkRefNum = kFileNotOpened ;
  142.     SInt16 resForkRefNum = kFileNotOpened ;
  143.     Handle hText = nil ;
  144.     Handle hStyles = nil ;
  145.     Handle hSoup = nil ;
  146.     Handle hFontTable = nil;
  147.     UInt32 theTime ;
  148.     Str255 tempFileName ;
  149.     FSSpec tempFileSpec ;
  150.     SInt16 tempVRef ;        // volume reference # for the temp file
  151.     SInt32 tempDirID ;        // directory ID of the temp file
  152.     OSErr err ;
  153.  
  154.     //    will we be replacing an existing file?
  155.     err = FSpGetFInfo( pFileSpec, &fileInfo ) ;
  156.     if ( err == noErr )
  157.     {
  158.         replacing = true;
  159.     }
  160.     else if ( err == fnfErr )
  161.     {
  162.         replacing = false;
  163.     }
  164.     else
  165.     {
  166.         goto cleanup;
  167.     }
  168.  
  169.     // originally, Marco had it so that if the file already existed (replacing == true)
  170.     // then just can the original file and move along.  for the scope of this demo, that
  171.     // really is ok, but generally speaking, not the Apple-recommended way of doing things.
  172.     // since we know we're under (at least) System 7 (due to WASTE's need of it), we know
  173.     // we can use temporary files, so let us do so!
  174.  
  175.     // also, Marco didn't check for locked files (technically, if a file is locked from
  176.     // the Finder, you shouldn't be able to modify it).  let's check for that.
  177.  
  178.     // if the file currently exists (meaning it was saved at some time in the past, be it
  179.     // 5 minutes ago, or 5 days ago), there is a chance that it could be locked (from the
  180.     // Finder's "Get Info" window (or otherwise).  If the file is locked, you cannot
  181.     // save changes.  Therefore, if 'replacing' is true, we have to throw up a message
  182.     // saying that we can't do this, then exit.
  183.  
  184.     if ( replacing )
  185.     {
  186.         if ( ( err = FSpCheckObjectLock ( pFileSpec ) ) != noErr )
  187.         {
  188.             goto cleanup ;
  189.         }
  190.  
  191.         // create the temporary file name.  the name doesn't have to make sense, just
  192.         // be unique
  193.  
  194.         GetDateTime ( & theTime ) ;
  195.         NumToString ( theTime, tempFileName ) ;
  196.  
  197.         // find the temporary items folder on the file's volume; create it if necessary
  198.         // it is important that the temp folder (and the temp file) and the "original" target
  199.         // file be on the same volume; if not, FSpExchangeFiles will return diffVolErr (-1303)
  200.         // and won't work
  201.  
  202.         if ( ( err = FindFolder ( pFileSpec -> vRefNum, kTemporaryFolderType, kCreateFolder, & tempVRef, & tempDirID ) ) != noErr )
  203.         {
  204.             goto cleanup ;
  205.         }
  206.  
  207.         // make an FSSpec for the temp file
  208.         err = FSMakeFSSpec ( tempVRef, tempDirID, tempFileName, & tempFileSpec ) ;
  209.         if ( (err != noErr) && (err != fnfErr ) )
  210.         {
  211.             goto cleanup ;
  212.         }
  213.     }
  214.  
  215.     //    create a new file.  if we're replacing, make a temp file.  if it's a
  216.     //  new file from the onset, just create the file
  217.  
  218.     // should we allow people to choose the file to create?  i.e. create a TEXT
  219.     // file or a ttro file?  if you'd like to do this, you'll want to find this
  220.     // info out when calling CustomPutFile() and pass that info to this function
  221.  
  222.     if ( replacing )
  223.     {
  224.         FSpCreateResFile( &tempFileSpec, sigWASTEDemo, kTypeText, smSystemScript );
  225.     }
  226.     else
  227.     {
  228.         FSpCreateResFile( pFileSpec, sigWASTEDemo, kTypeText, smSystemScript );
  229.     }
  230.  
  231.     if ((err = ResError()) != noErr)
  232.         goto cleanup;
  233.  
  234.     //  if replacing an old file, copy the old file information
  235.     if ( replacing )
  236.     {
  237.         if ( ( err = FSpSetFInfo( &tempFileSpec, &fileInfo ) ) != noErr )
  238.         {
  239.             goto cleanup;
  240.         }
  241.     }
  242.  
  243.     //    open the data fork for writing
  244.     if ( replacing )
  245.     {
  246.         err = FSpOpenDF( &tempFileSpec, fsRdWrPerm, &dataForkRefNum );
  247.     }
  248.     else
  249.     {
  250.         err = FSpOpenDF( pFileSpec, fsRdWrPerm, &dataForkRefNum );
  251.     }
  252.  
  253.     if ( err != noErr )
  254.     {
  255.         goto cleanup;
  256.     }
  257.  
  258.     //    set the end-of-file
  259.     if ( ( err = SetEOF( dataForkRefNum, 0 ) ) != noErr )
  260.     {
  261.         goto cleanup;
  262.     }
  263.  
  264.     //    set the position in the file to write from
  265.     if ( ( err = SetFPos( dataForkRefNum, fsFromStart, 0 ) ) != noErr )
  266.     {
  267.         goto cleanup;
  268.     }
  269.  
  270.     //    get the text handle from the WE instance
  271.     //    WEGetText returns the original handle, not a copy, so don't dispose of it!!
  272.     hText = WEGetText( we );
  273.     textSize = GetHandleSize( hText );
  274.  
  275.     //    write the text
  276.     HLock( hText );
  277.     err = FSWrite( dataForkRefNum, &textSize, *hText );
  278.     HUnlock( hText );
  279.  
  280.     if ( err != noErr )
  281.     {
  282.         goto cleanup;
  283.     }
  284.  
  285.     //    open the resource file for writing
  286.     if ( replacing )
  287.     {
  288.         resForkRefNum = FSpOpenResFile( &tempFileSpec, fsRdWrPerm );
  289.     }
  290.     else
  291.     {
  292.         resForkRefNum = FSpOpenResFile( pFileSpec, fsRdWrPerm );
  293.     }
  294.  
  295.     if ( ( err = ResError ( ) ) != noErr )
  296.     {
  297.         goto cleanup;
  298.     }
  299.  
  300.     //    allocate temporary handles to hold the style scrap, the soup
  301.     //    and the font table
  302.     //    try tapping temporary memory since WECopyRange() could get huge
  303.     if ( ( err = NewHandleTemp ( 0, & hStyles ) ) != noErr )
  304.     {
  305.         goto cleanup;
  306.     }
  307.     if ( ( err = NewHandleTemp ( 0, & hSoup ) ) != noErr )
  308.     {
  309.         goto cleanup;
  310.     }
  311.     if ( ( err = NewHandleTemp ( 0, & hFontTable ) ) != noErr )
  312.     {
  313.         goto cleanup ;
  314.     }
  315.  
  316.     //    create the style scrap and the soup
  317.     if ( ( err = WECopyRange ( 0, LONG_MAX, nil, ( StScrpHandle ) hStyles, hSoup, we ) ) != noErr )
  318.     {
  319.         goto cleanup ;
  320.     }
  321.  
  322.     //    create the font table
  323.     if ( ( err = WEBuildFontTable ( hFontTable, nil, we ) ) != noErr )
  324.     {
  325.         goto cleanup ;
  326.     }
  327.  
  328.     //    make them resource handles
  329.     AddResource ( hStyles, kTypeStyles, 128, "\p" ) ;
  330.     if ( ( err = ResError ( ) ) != noErr )
  331.     {
  332.         goto cleanup ;
  333.     }
  334.     AddResource ( hSoup, kTypeSoup, 128, "\p" ) ;
  335.     if ( ( err = ResError ( ) ) != noErr )
  336.     {
  337.         goto cleanup ;
  338.     }
  339.     AddResource ( hFontTable, kTypeFontTable, 128, "\p" ) ;
  340.     if ( ( err = ResError ( ) ) != noErr )
  341.     {
  342.         goto cleanup ;
  343.     }
  344.  
  345.     //    write them to the resource file
  346.     ChangedResource ( hStyles ) ;
  347.     WriteResource ( hStyles ) ;
  348.     if ( ( err = ResError ( ) ) != noErr )
  349.     {
  350.         goto cleanup ;
  351.     }
  352.     ChangedResource ( hSoup ) ;
  353.     WriteResource ( hSoup ) ;
  354.     if ( ( err = ResError ( ) ) != noErr )
  355.     {
  356.         goto cleanup ;
  357.     }
  358.     ChangedResource ( hFontTable ) ;
  359.     WriteResource ( hFontTable ) ;
  360.     if ( ( err = ResError ( ) ) != noErr )
  361.     {
  362.         goto cleanup ;
  363.     }
  364.  
  365.     //    "clean" this document by resetting the WE instance modification count
  366.     WEResetModCount ( we ) ;
  367.  
  368.     err = noErr;
  369.  
  370. cleanup:
  371.     // display an alert box if anything went wrong
  372.     if (err != noErr)
  373.     {
  374.         ErrorAlert( err );
  375.     }
  376.  
  377.     // remember, don't dispose the hText handle!
  378.     ForgetResource ( & hStyles ) ;
  379.     ForgetResource ( & hSoup ) ;
  380.     ForgetResource ( & hFontTable ) ;
  381.  
  382.     if ( dataForkRefNum != kFileNotOpened )
  383.     {
  384.         FSClose( dataForkRefNum ) ;
  385.         dataForkRefNum = kFileNotOpened ;
  386.     }
  387.  
  388.     if ( resForkRefNum != kFileNotOpened )
  389.     {
  390.         CloseResFile( resForkRefNum ) ;
  391.         resForkRefNum = kFileNotOpened ;
  392.     }
  393.  
  394.     if ( replacing )
  395.     {
  396.         // update the disk with any unwritten data
  397.  
  398.         FlushVol( nil, tempFileSpec.vRefNum );
  399.  
  400.         // since we were replacing an existing file, let's now swap the original
  401.         // and the temp file.  let's hear it for safe saves.
  402.  
  403.         if ( ( err = FSpExchangeFiles( &tempFileSpec, pFileSpec ) ) != noErr )
  404.         {
  405.             // handle the error
  406.             return err;
  407.         }
  408.  
  409.         // can the temp file since we don't need it anymore
  410.  
  411.         err = FSpDelete( &tempFileSpec );
  412.         if ( err != noErr )
  413.         {
  414.             // handle the error
  415.  
  416.             return err;
  417.         }
  418.     }
  419.  
  420.     // and update the disk with any unwritten data
  421.     FlushVol( nil, pFileSpec->vRefNum );
  422.  
  423.     return err;
  424. }
  425.  
  426.  
  427. /*    The following 2 functions (CheckObjectLock and FSpCheckObjectLock) were taken
  428.     from MoreFiles 1.2.1, a code sample from Apple's DTS.  Here's some info from
  429.     the MoreFiles readme:
  430.  
  431.         A collection of File Manager and related routines
  432.  
  433.         by Jim Luther, Apple Macintosh Developer Technical Support
  434.         with significant code contributions by Nitin Ganatra, Apple Macintosh Developer
  435.         Technical Support
  436.         MoreFile Reference is by Eric Soldan
  437.         Copyright © 1992-1994 Apple Computer, Inc.
  438.         All rights reserved.
  439.  
  440.     Frankly, this is one amazing repository of all sorts of file-related things.  I'd
  441.     check it out if you can. (should be, as of this writing, on ftp.info.apple.com
  442.     in like the /Apple.Support.Services/Developer_Support/ or something like that).
  443.  
  444.     thanx to Alex Rosen for answering my post on comp.sys.mac.programmer.help and pointing
  445.     out MoreFiles to me.
  446.  
  447.     WHAT DO THEY DO?  Oh duh...i should tell you huh?
  448.  
  449.     Both functions do the same thing:  check to see if the object is locked
  450.     (in this case, the object is a file).  This is using in WriteTextFile()
  451.     to prevent overwriting/deleting locked files.
  452.  
  453.     The only difference between these 2 functions are the arguments passed.
  454.     the first takes a vRefNum, dirID and a file name, the second takes an FSSpec
  455.     and then just calls the first based on the FSSpec (just makes for slighly
  456.     neater/readable code)
  457. */
  458.  
  459. pascal    OSErr    CheckObjectLock(SInt16 vRefNum, SInt32 dirID, StringPtr name)
  460. {
  461.     CInfoPBRec pb;
  462.     OSErr error;
  463.  
  464.     pb.hFileInfo.ioNamePtr = name;
  465.     pb.hFileInfo.ioVRefNum = vRefNum;
  466.     pb.hFileInfo.ioDirID = dirID;
  467.     pb.hFileInfo.ioFDirIndex = 0;    // use ioNamePtr and ioDirID
  468.     error = PBGetCatInfoSync(&pb);
  469.  
  470.     if ( error == noErr )
  471.     {
  472.         // check locked bit
  473.         if ( (pb.hFileInfo.ioFlAttrib & 0x01) != 0 )
  474.             error = fLckdErr;
  475.     }
  476.     return ( error );
  477. }
  478.  
  479. /*****************************************************************************/
  480.  
  481. pascal    OSErr    FSpCheckObjectLock(const FSSpec *spec)
  482. {
  483.     return ( CheckObjectLock(spec->vRefNum, spec->parID, (StringPtr) spec->name) );
  484. }
  485.  
  486.